const Arima = require('arima')

const autoARIMA = (data) => {
  let bestAIC = Infinity // 初始化最优 AIC（误差度量）为正无穷，表示尚未找到最优模型
  let bestModel = null // 用于存储最优的 ARIMA 模型
  let bestP = 0 // 用于存储最优 ARIMA 模型的 p 参数
  let bestD = 0 // 用于存储最优 ARIMA 模型的 d 参数
  let bestQ = 0 // 用于存储最优 ARIMA 模型的 q 参数

  // 网格搜索遍历 p, d, q 参数的不同组合
  for (let p = 0; p <= 5; p++) {
    // 遍历自回归阶数 p
    for (let d = 0; d <= 2; d++) {
      // 遍历差分次数 d
      for (let q = 0; q <= 5; q++) {
        // 遍历移动平均阶数 q
        try {
          console.log(`训练 ARIMA(${p},${d},${q})...`) // 打印当前训练的 ARIMA 模型参数
          const model = new Arima({ p, d, q }) // 创建 ARIMA 模型实例，传入当前的 p, d, q 参数
          model.train(data) // 用历史数据训练模型

          // 使用预测结果来评估模型
          const forecast = model.predict(1) // 预测下一个值（未来一个时间点）
          const actual = data[data.length - 1] // 获取实际数据中的最后一个值作为真实值
          const error = Math.abs(forecast[0] - actual) // 计算预测值与实际值之间的误差（取绝对值）

          console.log(`ARIMA(${p},${d},${q}) 预测误差: ${error}`) // 打印当前模型的预测误差

          // 如果当前模型的误差比最优误差更小，则更新最优模型及其参数
          if (error < bestAIC) {
            bestAIC = error // 更新最优 AIC
            bestModel = model // 更新最优模型
            bestP = p // 更新最优 p 参数
            bestD = d // 更新最优 d 参数
            bestQ = q // 更新最优 q 参数
          }
        } catch (error) {
          // 捕捉训练过程中的错误
          console.log(`ARIMA(${p},${d},${q}) 训练失败:`, error) // 打印训练失败的错误信息
        }
      }
    }
  }

  // 如果没有找到有效的模型，输出提示信息
  if (bestModel === null) {
    console.log('没有找到有效的模型，检查数据或调整参数范围')
  } else {
    console.log(`找到最优模型: ARIMA(${bestP},${bestD},${bestQ})`) // 输出最优模型的参数
  }

  return { bestModel, bestP, bestD, bestQ } // 返回最优模型及其参数
}

// 示例数据
const historicalData = [22, 21, 23, 24, 22, 21, 25, 23, 24, 22, 21, 23, 22, 21, 24]

// 调用 autoARIMA 方法
const { bestModel, bestP, bestD, bestQ } = autoARIMA(historicalData)
console.log(`最优模型为 ARIMA(${bestP},${bestD},${bestQ})`)

// 使用最优模型进行未来预测
if (bestModel) {
  const futurePredictions = bestModel.predict(24)
  console.log('未来 24 个预测值:', futurePredictions)
}
